

/*
 * @Author       : DonnieLiang
 * @Date         : 2024-11-11
 * @Version      : 1.0
 * @Description  : tcp_client_app
 */


#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

#include <memory.h> /*使用memcpy所需的头文件*/

#include <time.h>

#include <sys/types.h>
#include <sys/socket.h>

// #include <netinet/in.h>
// #include <arpa/inet.h>
// #include <pthread.h>  

#include <pthread.h>  


#include "iotv30_config.h"


#include "led.h"
#include "proto_plat.h"
#include "rtc_calendar.h"
#include "tcp_api_01.h" 


#include "iotv30_tcp_client.h" 
#include "uart_printf.h"

 


 
 //TCP Client 测试全局状态标记变量
 //bit7:0,没有数据要发送;1,有数据要发送 
 //bit6:0,没有收到数据;1,收到数据了.
 //bit5:0,没有连接上服务器;1,连接上服务器了.
 //bit4~0:保留
  
 static tcp_client_flag_u	tcp_client_flag ;
 static uint8_t             ucTcp_ClientStep = 0;	


void iotv30_Tcp_Client_Init(void)
{
  tcp_client_flag.all = 0;
  ucTcp_ClientStep    = 0;	
	
}



//返回值 0---链接断开，  1---链接成功
 uint8_t iotv30_IsTcpClientConnected( void )
{
    return tcp_client_flag.bit.link;
}



void iotv30_TCP_Reset( void )
{
  tcp_client_flag.bit.reset = 1;	
  tcp_client_flag.bit.link  = 0;

}

void iotv30_TCP_link_led_tick(void )
{
uint8_t  static status = 0;

   if( tcp_client_flag.bit.link  )
   { 
	  status = ~status;
	  if( status )
	  {
		LED_Link_On( );  
	  }else{
		LED_Link_Off( );  
	  }

   }else{
	  LED_Link_Off( );  
   }

}




//---------主进程---------------------
 uint16_t iotv30_Tcp_Client_App_Process(ClientInfo_st* pinfo)
{	
//uint16_t ret;

	 switch( ucTcp_ClientStep ) 													
	 {
			case 0:  // 	case SOCK_CLOSED:			  //socket处于关闭状态
			{								
					 //if( 0 != IsEth_LinkDone( ) ) 
                     //LED_Link_Off( );  
					 if( tcp_client_connect(pinfo ) > 0 )  //  tcp_connect()
					 {						  
						  tcp_client_flag.bit.link  = 1;
						  printf("tcp connect ok: socket_fd= %d\n\r", pinfo->fd );	
						  printf("tcp_client_flag.bit.link = %d\n\r", tcp_client_flag.bit.link );		
						  ucTcp_ClientStep++;

						  return 1;//创建线程

					 }else{  //无法连接----1sec 后再重新链接
						//LED_Link_Off( );  
					     /*usleep函数将该进程挂起一定时间，单位微秒，头文件unistd.h*/
					    // usleep(100000);
						// sleep(1);   //感觉这里的延迟不起作用    

					 }
														
			} break;
					
						
			case 1:  // 创建接收线程	???
			{							
			    ucTcp_ClientStep++;
			} break;
			
					
		  case 2:  // 	
		  {								

		        if( 0 == tcp_client_flag.bit.link  ) 
				{ //链接已经断开	
                    // LED_Link_Off( );  
				     printf("iotv30 tcp socket close\n\r");
					 printf("iotv30 tcp_client_flag.bit.link=%d\n\r", tcp_client_flag.bit.link );
				 
					 ucTcp_ClientStep = 0; //重新建立链接	
					
				}else if( 0 != tcp_client_flag.bit.reset )
				{ //主动断开链接	
				  // LED_Link_Off( );  	
				   printf("iotv30 tcp socket reset\n\r");			
				   tcp_client_flag.bit.reset = 0;	
				   tcp_client_flag.bit.link  = 0;
				
				   ucTcp_ClientStep = 0; //重新建立链接						
									
				}else{ //正常链接----发送数据给服务器 
					

#if 0    //ver.1.45

					if( 0 != Tcp_TxData[TCP_API_CH_IOTV30].Flag )//是否有数据需要发送
					{					
						
                         //发送数据，最后一个参数为 0 时，可以用 write() 替代（ send 等同于 write ）						
							//write(pinfo->fd, Tcp_TxData[TCP_API_CH_IOTV30].Buff , Tcp_TxData[TCP_API_CH_IOTV30].Len );		
							ret = send(pinfo->fd, Tcp_TxData[TCP_API_CH_IOTV30].Buff , Tcp_TxData[TCP_API_CH_IOTV30].Len , 0 );
			
							if ( ret != Tcp_TxData[TCP_API_CH_IOTV30].Len  )
							{						
								printf("iotv30 server offline ret=%d,len=%d\n\r",ret,Tcp_TxData[TCP_API_CH_IOTV30].Len);   // //---这里报错----????-------------------------   
								close(pinfo->fd);
							
								ucTcp_ClientStep = 0; //重新建立链接	

							}else{
								printf("iotv30  socket send done\n\r");
							}
									
												
						 Tcp_TxData[TCP_API_CH_IOTV30].Len = 0;
						 Tcp_TxData[TCP_API_CH_IOTV30].Flag = 0;
					}

#endif			  


				}
				
																											
		}break; 				
				
		
				
		default:
		{				
			ucTcp_ClientStep = 0 ;		
			
		}break; 			
			
				
	}  // switch( ucTcp_ClientStep )	

	 
 return 0;//不需要创建线程	

	
} 


 
// 阻塞等待服务器的数据，超时返回0
static int select_read_from_server(int fd)
{
    fd_set read_fds;
	struct timeval timeout;
    FD_ZERO(&read_fds);
    FD_SET(fd, &read_fds);
	memset(&timeout, 0, sizeof(struct timeval));

    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    return select(fd + 1, &read_fds, NULL, NULL, &timeout);
}
  
 ///----------------接收进程-----------------------


 
  /***********************************************
  函数名：Tcp_Client_RecvProcess
  功能：负责监测接收来自服务器的数据  
  参数：sockfd -- 套接字描述符
  输出：把收到的socket数据保存，并传给上级
 
  返回值：null
  *************************************************/

void iotv30_Tcp_Client_RecvProcess(int *sockfd)
  {
	  int connfd = *sockfd;
      ssize_t nRead;
	  memset(&hplat_comm, 0, sizeof(plat_comm_t));

	 //  LOG_NAME(); 
 
	  printf("%s 子线程ID: %ld\n\r",__FUNCTION__, pthread_self());


	  while(1)
	  {
		   plat_conn_manager( );  //////=======登录心跳逻辑============

		   if (select_read_from_server(connfd) == 0) {
			   continue;
		   }

		  /*接收服务器发来的消息*/
		  //   Returns the number read or -1 for errors.
		  nRead = recv(connfd , Tcp_RxData[TCP_API_CH_IOTV30].Buff , TCP_CLIENT_RX_BUFSIZE , 0);

		  /*recv函数返回值: <0 出错	;=0 链接关闭  ;>0接收到的字节数 */
		  //Returns the number read or -1 for errors.
		  if( nRead <= 0 )
		  {//服务器已经不在线
			  		  
			  if(nRead == 0)
			  {
				printf("ch_iotv30 server offline!nRead=%zd\n\r",nRead );   
			  }else{
				printf("ch_iotv30 server error!nRead=%zd\n\r",nRead );   
			  }

		      Tcp_RxData[TCP_API_CH_IOTV30].Len = 0;
			  close(connfd);
			  *sockfd = -1;
			  tcp_client_flag.bit.link	= 0;
			  pthread_exit(0); //退出当前线程
			  //exit(0);
				
		  }else{

			 Tcp_RxData[TCP_API_CH_IOTV30].Len = nRead;

#if  0  // DEBUG_PRINT_ENABLE  		
			RTC_Prinft_Now( );					   
			logout( " ETH_%d CH_IOTV30 Rx:\n",TCP_API_CH_IOTV30);

           printf("Tcp_Client_Recv data form server: data_len=%d\n",Tcp_RxData[TCP_API_CH_IOTV30].Len);	
           printf("%s\n",Tcp_RxData[TCP_API_CH_IOTV30].Buff);
#endif	

	 
#if   DEBUG_PRINT_ENABLE  		//----------打印16进制格式-------
										   
					RTC_Prinft_Now( );					   
					logout( " ETH_%d ch_iotv30 Rx: len=%d\n",TCP_API_CH_IOTV30, Tcp_RxData[TCP_API_CH_IOTV30].Len);					
					UartPrintHex2String( Tcp_RxData[TCP_API_CH_IOTV30].Buff , Tcp_RxData[TCP_API_CH_IOTV30].Len);  
					UartPrintString( "\n\r"); 
//					UartPrintString( "\n\r cmd =	");
//					UartPrintHex2String( &Tcp_RxData[TCP_API_CH_IOTV30].Buff[10], 1);	
//			 ETH Rx: 
//68 00 14 00 00 07 80 68 80 02 f0 01 de 16 		

#endif	

				Tcp_RxData[TCP_API_CH_IOTV30].Flag  = 1;	

				tlv_recv_handler((uint8_t*)&Tcp_RxData[TCP_API_CH_IOTV30].Flag,Tcp_RxData[TCP_API_CH_IOTV30].Buff, Tcp_RxData[TCP_API_CH_IOTV30].Len, 0);       ///////------上行协议的核心处理句柄----------------------
				// Server_RxData.Len = 0;

				// memset(Tcp_RxData[TCP_API_CH_IOTV30].Buff, 0, Tcp_RxData[TCP_API_CH_IOTV30].Len);
				// Tcp_RxData[TCP_API_CH_IOTV30].Len = 0;

		  	}


         //usleep(13000);
 		//sleep(5);
		  
	  /*usleep函数将该进程挂起一定时间，单位微秒，头文件unistd.h*/
	  // usleep(100000);


	}//while	  
 
 
	  
}
 
 











